package Behavioral.Observer.eventQueue;

///* EventQueue.java
//
//	Purpose:
//
//	Description:
//
//	History:
//		Fri May  2 15:35:25     2008, Created by tomyeh
//
//Copyright (C) 2008 Potix Corporation. All Rights Reserved.
//
//{{IS_RIGHT
//}}IS_RIGHT
//*/

///**
// * An event queue.
// * An event queue is a many-to-many 'channel' to publish events and to subscribe
// * event listeners ({@link EventListener}).
// *
// * <h3><a name="async_sync"></a>Asynchronous and Synchronous Event Listeners</h3>
// *
// * <p>There are two kinds of event listeners: synchronous and asynchronous.
// * A synchronous listener works the same as a normal event listener
// * (listeners registered to a component ({@link org.zkoss.zk.ui.Component#addEventListener}).
// * It is executed one-by-one. No two event listeners belonging to the same desktop
// * will be executed at the same time.
// * In additions, it is invoked under an execution (i.e., {@link org.zkoss.zk.ui.Executions#getCurrent} never null).
// * It is allowed to manipulate the components belonging
// * to the current execution.
// * <p>On the other hand, an asynchronous listener is executed asynchronously
// * in another thread.
// * It can <i>not</i> access the components belonging to any desktop.
// * There is no current execution ({@link org.zkoss.zk.ui.Executions#getCurrent} is null}.
// * However, it is useful to make the application more responsive when
// * executing a long operation. A typical use is to execute the long operation
// * in an asynchronous listener, and then all other events can be processed
// * concurrently.
// * @author tomyeh
// * @since 5.0.0
// */
//public interface EventQueue<T extends Event> {
public interface EventQueue{

//    /** Publishes an event to the queue.
//     *
//     * <p>If the scope of a event queue is desktop or group,
//     * this method must be called within an activated execution
//     * (i.e., {@link org.zkoss.zk.ui.Executions#getCurrent} not null),
//     * or in an asynchronous listener (see {@link EventQueue}).
//     *
//     * <p>On the other hand, if the scope is session or application,
//     * it is OK to be called without the current execution.
//     *
//     * @param event the event to publish.<br/>
//     * Notice that all subscribers will receive the event no matter
//     * what the event's name and target are.<br/>
//     * You could publish an anonymous event by
//     * <code>publish(new Event("", null, data))</code>.
//     * @exception IllegalStateException if this method is called
//     * not within an activated execution (such as a working thread),
//     * and this is a ({@link EventQueues#DESKTOP}) or {@link EventQueues#GROUP}
//     * event queue.
//     */
//    public void publish(T event);
//
//    /** Subscribes a listener to this queue.
//     * It is the same as <code>subscribe(listener, false)</code>
//     * ({@link #subscribe(EventListener,boolean)}. In other words,
//     * it subscribes a synchronous listener.
//     *
//     * <p>Note: this method must be called within an activated execution
//     * (i.e., {@link org.zkoss.zk.ui.Executions#getCurrent} not null),
//     * no matter what scope the event queue is.
//     *
//     * <p>Note: the listener could access the component associated with the event
//     * ({@link Event#getTarget}), only if this is an {@link EventQueues#DESKTOP}
//     *event queue.
//     *
//     * <p>An event listener can be subscribed multiple times, and
//     * it will be invoked multiple times if an event is published.
//     *
//     * <p>Even if this is a {@link EventQueues#GROUP}, {@link EventQueues#SESSION},
//     * or {@link  EventQueues#APPLICATION} event queue,
//     * the listener is subscribed for the current desktop only, i.e.,
//     * it can only access the components belong to the subscribed desktop.
//     * If you want to use the same listener to manipulate multiple desktops,
//     * you have to subscribe them separately when the corresponding
//     * execution is available.
//     * @see #subscribe(EventListener,EventListener)
//     * @see #subscribe(EventListener,boolean)
//     */
//    public void subscribe(EventListener<T> listener);
//
//    /** Subscribes a synchronous or asynchronous listener to this event queue.
//     * A synchronous listener works the same as a normal event listener,
//     * while an asynchronous listener is executed asynchronously in an working thread.
//     * Refer <a href="#async_sync">here</a> for details.
//     * <p>Here is an example,
//     <pre><code>
//     &lt;window title="long operation" border="normal">
//     &lt;zscript>
//     void print(String msg) {
//     new Label(msg).setParent(inf);
//     }
//     &lt;/zscript>
//     &lt;button label="async long op">
//     &lt;attribute name="onClick">&lt;![CDATA[
//     if (EventQueues.exists("longop")) {
//     print("It is busy. Please wait");
//     return; //busy
//     }
//
//     EventQueue eq = EventQueues.lookup("longop"); //create a queue
//     String result;
//
//     //subscribe async listener to handle long operation
//     eq.subscribe(new EventListener() {
//     public void onEvent(Event evt) { //asynchronous
//     org.zkoss.lang.Threads.sleep(3000); //simulate a long operation
//     result = "success"; //store the result
//     }
//     }, new EventListener() { //callback
//     public void onEvent(Event evt) {
//     print(result); //show the result to the browser
//     EventQueues.remove("longop");
//     }
//     });
//
//     print("Wait for 3 seconds");
//     eq.publish(new Event("whatever")); //kick off the long operation
//     ]]>&lt;/attribute>
//     &lt;/button>
//     &lt;vbox id="inf"/>
//     &lt;/window>
//     </code></pre>
//     *
//     * <p>Notice that, though an asynchronous listener cannot access
//     * the desktop and has no current execution, it can invoke
//     * {@link #publish} to publish the events. Refer to
//     * another example in {@link #subscribe(EventListener,boolean)}.
//     *
//     * @param listener the asynchronous listener to invoke when an event
//     * is received
//     * @param callback the callback listener, which will be invoked if
//     * the asynchronous listen has been invoked.
//     * Unlike the asynchronous listener, the callback listener works
//     * like a normal listener. You can access the current execution,
//     * and update the desktop.<br/>
//     * <b>Version Difference</b>: since 5.0.8, the event argument is the same
//     * as the one passed to <code>listener</code>. In the prior version,
//     * it is always null for the callback listener.
//     * @see #subscribe(EventListener)
//     * @see #subscribe(EventListener,boolean)
//     */
//    public void subscribe(EventListener<T> listener, EventListener<T> callback);
//
//    /** Subscribes a synchronous or asynchronous listener to this event queue.
//     * A synchronous listener works the same as a normal event listener,
//     * while an asynchronous listener is executed asynchronously in an working thread.
//     * Refer <a href="#async_sync">here</a> for details.
//     * <p>The use of synchronous listeners is straightforward -- they
//     * are just the same a normal event listener.
//     * Here is an example of using an asynchronous listener. In this example,
//     * we use an asynchronous listener to execute a long operation,
//     * a synchronous listener to update the desktop, and they communicate
//     * with each other with events.
//     * <p>There is another way to do the same job, callback, refer
//     * to {@link #subscribe(EventListener,EventListener)} for example.
//     * <pre><code>
//     &lt;window title="long operation" border="normal"&gt;
//     &lt;zscript&gt;
//     void print(String msg) {
//     new Label(msg).setParent(inf);
//     }
//     &lt;/zscript&gt;
//     &lt;button label="async long op"&gt;
//     &lt;attribute name="onClick"&gt;&lt;![CDATA[
//     if (EventQueues.exists("longop")) {
//     print("It is busy. Please wait");
//     return; //busy
//     }
//
//     EventQueue eq = EventQueues.lookup("longop"); //create a queue
//     String result;
//
//     //subscribe async listener to handle long operation
//     eq.subscribe(new EventListener() {
//     public void onEvent(Event evt) {
//     if ("doLongOp".equals(evt.getName())) {
//     org.zkoss.lang.Threads.sleep(3000); //simulate a long operation
//     result = "success"; //store the result
//     eq.publish(new Event("endLongOp")); //notify it is done
//     }
//     }
//     }, true); //asynchronous
//
//     //subscribe a normal listener to show the result to the browser
//     eq.subscribe(new EventListener() {
//     public void onEvent(Event evt) {
//     if ("endLongOp".equals(evt.getName())) {
//     print(result); //show the result to the browser
//     EventQueues.remove("longop");
//     }
//     }
//     }); //synchronous
//
//     print("Wait for 3 seconds");
//     eq.publish(new Event("doLongOp")); //kick off the long operation
//     ]]&gt;&lt;/attribute&gt;
//     &lt;/button&gt;
//     &lt;vbox id="inf"/&gt;
//     &lt;/window&gt;
//     </code></pre>
//     * <p>The asynchronous event listener requires Server Push
//     * ({@link org.zkoss.zk.ui.sys.ServerPush}).
//     * <p>If you want to show a busy message to cover a portion of the desktop,
//     * use {@link org.zkoss.zk.ui.util.Clients#showBusy(org.zkoss.zk.ui.Component,String)}
//     * <p>Note: this method must be called within an activated execution,
//     * i.e., {@link org.zkoss.zk.ui.Executions#getCurrent} not null.
//     * <p>An event listener can be subscribed multiple times, and
//     * it will be invoked multiple times if an event is published.
//     *
//     * <p>Even if this is an application-level or session-level event queue,
//     * the listener is subscribed for the current desktop only.
//     * If you want to use the same listener for multiple desktops,
//     * you have to subscribe them separately when the corresponding
//     * execution is available.
//     * @param listener the listener
//     * @param async whether the listener is asynchronous
//     * @see #subscribe(EventListener)
//     * @see #subscribe(EventListener, EventListener)
//     */
//    public void subscribe(EventListener<T> listener, boolean async);
//    /** Unsubscribes a listener from the queue.
//     *
//     * <p>Note: this method must be called within an activated execution,
//     * i.e., {@link org.zkoss.zk.ui.Executions#getCurrent} not null.
//     *
//     * <p>Notice that this method only unsubscribes the listener
//     * subscribed for this desktop. It doesn't check the listeners
//     * for other desktops even if this is an application-level or
//     * session-level event queue.
//     *
//     * @return true if the listener was subscribed.
//     */
//    public boolean unsubscribe(EventListener<T> listener);
//
//    /** Returns if an event listener is subscribed.
//     * <p>Notice that this method only checks the listeners
//     * subscribed for this desktop. It doesn't check the listeners
//     * for other desktops even if this is an application-level or
//     * session-level event queue.
//     */
//    public boolean isSubscribed(EventListener<T> listener);
//    /** Closes the event queue.
//     * After closed, application cannot access any of its method.
//     * <p>Don't call this method directly. It is called only internally.
//     * Rather, use {@link EventQueues#remove} instead.
//     */
//    public void close();
//    /** Returns whether it is closed.
//     * @since 5.0.6
//     */
//    public boolean isClose();
}
